var crypto  = require('crypto');
var util    = require('util');
var url     = require('url');
var http    = require('http');
var https   = require('https');

var common  = require('./common.js');
var config      = require(require('fs').existsSync('../config.js') ? '../config.js' : './config.js');

var appkey = 'cd5f316034965d0a0e51dcbb97e116d1';
var appid = 100712667;

function startWebServer(){
    // 创建支付QQ回调服务器
    http.createServer(function(req, res) {
        if( req.method == 'POST' ) {
            req.connection.destroy();
            return;
        }

        req.on('end', function() {
            var query = url.parse(req.url, true).query || {};
            if( req.url.startWith('/task_v3') ) {
                handleTaskV3Req(query, res);
                return;
            }
            if( req.url.startWith('/task') ) {
                handleTaskReq(query, res);
                return;
            }
            if( req.url.startWith('/market') ) {
                handleMarketReq(query, res);
                return;
            }
            if( req.url.startWith('/tw_pay') ) {
                handleTWPayReq(query, res);
                return;
            }
            if( req.url.startWith('/jinzhu_pay') ) {
                handleJinzhuPayReq(query, res);
                return;
            }
            if( req.url.startWith('/query_cash') ) {
                handleQueryCashReq(query, res);
                return;
            }
            if( req.url.startWith('/query_user') ) {
                handleQueryUserReq(query, res);
                return;
            }

            if( req.url.startWith('/check_user') ) {
                handleCheckUser(query, res);
                return;
            }

            handlePayReq(query, res);
        });

        req.resume();

    }).listen(config.PayListen, config.PayHost);
}

function handleTaskReq(req, res) {
    var openid = req.openid;
    var existUid = gUsers[openid];
    if( !existUid ) {
        res.writeHead(200, common.htmlHeaders);
        res.end(util.format('%j', {ret:1, msg:'user not login'}));
        return;
    }

    // 请求game数据
    var url = util.format('%s?mod=gm&act=task_complete&uid=%d&args=%j',
            getGameServer(existUid), existUid, {key:config.GMAuth});

    common.httpGet(url, function(data){
        var resp = {ret:0, msg:'OK', zoneid:config.ServerId};
        if( !data || data.code != 0 ) {
            resp.ret = 1; resp.msg='not finish';
        }

        res.writeHead(200, common.htmlHeaders);
        res.end(util.format('%j', resp));
    }, true);
}

function handleTaskV3Req(req, res) {
    var openid = req.openid;
    var existUid = gUsers[openid];
    if( !existUid ) {
        res.writeHead(200, common.htmlHeaders);
        res.end(util.format('%j', {ret:1, msg:'user not login'}));
        return;
    }

    var cmd = req.cmd;
    // 请求game数据
    var url = util.format('%s?mod=gm&act=task_v3&uid=%d&args=%j',
            getGameServer(existUid), existUid, {key:config.GMAuth, cmd:cmd, step:req.step});

    common.httpGet(url, function(data){
        var resp = {ret:0, msg:'OK', zoneid:config.ServerId};
        if( !data || data.code != 0 ) {
            resp.ret = 1; resp.msg='error';
        }else{
            resp.ret = data.data.ret;
        }

        if( resp.ret != 0 ) {
            delete resp.msg;
        }

        res.writeHead(200, common.htmlHeaders);
        res.end(util.format('%j', resp));
    }, true);
}

function handleMarketReq(req, res) {
    var openid = req.openid;
    var existUid = gUsers[openid];
    if( !existUid ) {
        res.writeHead(200, common.htmlHeaders);
        res.end(util.format('%j', {ret:1, msg:'user not login'}));
        return;
    }

    // 请求game数据
    var url = util.format('%s?mod=gm&act=market_diamond&uid=%d&args=%j',
            getGameServer(existUid), existUid, {key:config.GMAuth});

    common.httpGet(url, function(data){
        var resp = {ret:0, msg:'OK'};
        if( !data || data.code != 0 ) {
            resp.ret = 1; resp.msg='error';
        }

        res.writeHead(200, common.htmlHeaders);
        res.end(util.format('%j', resp));
    }, true);
}

function handlePayReq(req, res) {
    
    var openid = req.openid;
    var openkey = gOpenkeys[openid];
    var existUid = gUsers[openid];
    if( !openkey || !existUid ) {
        res.writeHead(200, common.htmlHeaders);
        res.end(util.format('%j', {ret:1, msg:'user not login'}));
        return;
    }
    
    var gid = req.payitem.split('*')[0];
    var cash = +gid;

    // 新建支付记录
    // 支付state 0:完成 1:新支付 2:confirm失败
    var record = {
        openid: openid, 
        billno: req.billno, 
        gid: gid, 
        cash: cash,
        ts: req.ts,
        time: (new Date()).format('yyyy-MM-dd hh:mm:ss'),
        amt: req.amt, 
        state: 1
    };

    gDBPay.insert(record, function(err, result){
        if( err || result.length < 1 ) {
            res.writeHead(200, common.htmlHeaders);
            res.end(util.format('%j', {ret:1, msg:'add pay record error'}));
            return;
        }

        var id = result[0]._id;

        // 请求game数据
        var url = util.format('%s?mod=gm&act=pay&uid=%d&args=%j',
                getGameServer(existUid), existUid, {key:config.GMAuth, cash:cash, billno:req.billno, amt:req.amt});

        common.httpGet(url, function(data){
            var resp = {ret:0, msg:'OK'};
 
            if( data && data.code == 0 ) {
                var ip = (data.data && data.data.ip) || "0.0.0.0";
                reportQQ('recharge', {'opuid':existUid, 'modifyfee':req.amt}, data.pf);
                confirmDelivery(openid, openkey, req, function(data){
                    if( data && data.ret == 0 ) {
                        onPayConfirmd(id, ip, true);
                        return;
                    }

                    // 重试
                    confirmDelivery(openid, openkey, req, function(data){
                        onPayConfirmd(id, ip, data && data.ret == 0);
                    });
                });
            }else{
                resp.ret = 1;
                resp.msg = 'add cash error';
            }

            res.writeHead(200, common.htmlHeaders);
            res.end(util.format('%j', resp));
        }, true);
    });

}

function handleTWPayReq(req, res) {
    
    var openid = req.openid;
    var existUid = gUsers[openid];
    if( !existUid ) {
        res.writeHead(200, common.htmlHeaders);
        res.end(util.format('%j', {ret:2, msg:'user not exist'}));
        return;
    }
    
    var gid = req.payitem.split('*')[0];
    var cash = +gid;

    // 新建支付记录
    // 支付state 0:完成 1:新支付 2:confirm失败
    var record = {
        _id: req.billno,
        openid: openid, 
        billno: req.billno, 
        gid: gid, 
        cash: cash,
        ts: req.ts,
        time: (new Date()).format('yyyy-MM-dd hh:mm:ss'),
        amt: req.amt, 
        state: 1
    };

    gDBPay.insert(record, function(err, result){
        gDBPay.findOne({_id:record._id},{}, function(err, result){
            if( err || !result ) {
                res.writeHead(200, common.htmlHeaders);
                res.end(util.format('%j', {ret:1, msg:'add pay record error'}));
                return;
            }

            if( result.state == 0 ) {
                res.writeHead(200, common.htmlHeaders);
                res.end(util.format('%j', {ret:5, msg:'finished'}));
                return;
            }

            var id = record._id;

            // 请求game数据
            var url = util.format('%s?mod=gm&act=pay&uid=%d&args=%j',
                    getGameServer(existUid), existUid, {key:config.GMAuth, cash:cash, billno:req.billno, amt:req.amt});

            common.httpGet(url, function(data){
                var resp = {ret:0, msg:'OK'};

                if( data && data.code == 0 ) {
                    var ip = data.data.ip || "0.0.0.0";
                    gDBPay.findAndModify({_id:id}, [], {$set:{'state':0, 'ip':ip}}, {}, function(err, doc){
                    });
                }else{
                    resp.ret = 7;
                    resp.msg = 'add cash error';
                }


                res.writeHead(200, common.htmlHeaders);
                res.end(util.format('%j', resp));
            }, true);
        });
    });
}

function handleJinzhuPayReq(req, res) {

    var openid = req.openid;
    var existUid = gUsers[openid];
    if( !existUid ) {
        res.writeHead(200, common.htmlHeaders);
        res.end(util.format('%j', {ret:2, msg:'user not exist'}));
        return;
    }

    var cash = req.cash;

    // 新建支付记录
    // 支付state 0:完成 1:新支付 2:confirm失败
    var record = {
        _id: req.billno,
        openid: req.openid,
        billno: req.billno,
        gid: cash,
        cash: cash,
        ts: req.ts,
        time: (new Date()).format('yyyy-MM-dd hh:mm:ss'),
        amt: req.amt,
        fencheng: req.fencheng,
        state: 1
    };

    gDBPay.insert(record, function(err, result){
        gDBPay.findOne({_id:record._id},{}, function(err, result){
            if( err || !result ) {
                res.writeHead(200, common.htmlHeaders);
                res.end(util.format('%j', {ret:1, msg:'add pay record error'}));
                return;
            }

            if( result.state == 0 ) {
                res.writeHead(200, common.htmlHeaders);
                res.end(util.format('%j', {ret:5, msg:'finished'}));
                return;
            }

            var id = record._id;

            // 请求game数据
            var url = util.format('%s?mod=gm&act=pay&uid=%d&args=%j',
                getGameServer(existUid), existUid, {key:config.GMAuth, cash:cash, billno:req.billno, amt:req.amt});

            common.httpGet(url, function(data){
                var resp = {ret:0, msg:'OK'};

                if( data && data.code == 0 ) {
                    var ip = data.data.ip || "0.0.0.0";
                    gDBPay.findAndModify({_id:id}, [], {$set:{'state':0, 'ip':ip}}, {}, function(err, doc){
                    });
                }else{
                    resp.ret = 7;
                    resp.msg = 'add cash error';
                }


                res.writeHead(200, common.htmlHeaders);
                res.end(util.format('%j', resp));
            }, true);
        });
    });
}

function handleQueryCashReq(req, res) {
    var openid = req.openid;
    var existUid = gUsers[openid];
    if( !existUid ) {
        res.writeHead(200, common.htmlHeaders);
        res.end(util.format('%j', {ret:1, msg:'user not login'}));
        return;
    }

    // 请求game数据
    var url = util.format('%s?mod=gm&act=query_cash&uid=%d&args=%j',
            getGameServer(existUid), existUid, {key:config.GMAuth});

    common.httpGet(url, function(data){
        var resp = {ret:0, cash:0};
        if( !data || data.code != 0 ) {
            resp.ret = 1; resp.msg='fail';
        }else{
            resp.cash = data.data.cash;
        }

        res.writeHead(200, common.htmlHeaders);
        res.end(util.format('%j', resp));
    }, true);
}

function onPayConfirmd(id, ip, succ) {
    var state = succ ? 0:2;
    gDBPay.findAndModify({_id:id}, [], {$set:{'state':state, 'ip': ip}}, {}, function(err, doc){
    });
}

function urlencode(content) {
    return encodeURIComponent(content).replace(/\*/g, '%2A');
}

function buyGoods(openid, openkey, pf, pfkey, gid, callback, manyouid) {
    var method = 'POST';
    var url = '/v3/pay/buy_goods';
    
    var amt = gid;
    var appmode = 1;
    var payitem = util.format('%s*%s*1', gid, gid); // ID*price*num
    var goodsmeta = util.format('%s元宝*元宝', gid);
    var goodsurl = util.format('http://app100645087.imgcache.qzoneapp.com/app100712667/image/cash%s.png', gid);
    var pf = pf || 'qzone';
    var zoneid = config.ServerId;
    var ts = common.getTime();

    var strParam = util.format('amt=%d&appid=%s&appmode=%d&goodsmeta=%s&goodsurl=%s&openid=%s&openkey=%s&payitem=%s&pf=%s&pfkey=%s&ts=%d&zoneid=%d', amt, appid, appmode, goodsmeta, goodsurl, openid, openkey, payitem, pf, pfkey, ts, zoneid); 
    if( manyouid ) {
       strParam = util.format('amt=%d&appid=%s&appmode=%d&goodsmeta=%s&goodsurl=%s&manyouid=%s&openid=%s&openkey=%s&payitem=%s&pf=%s&pfkey=%s&ts=%d&zoneid=%d', amt, appid, appmode, 
            goodsmeta, goodsurl, manyouid, openid, openkey, payitem, pf, pfkey, ts, zoneid);
    }

    var sigParam = util.format('%s&%s&%s', method, urlencode(url), urlencode(strParam));
    var hmac = crypto.createHmac('sha1', appkey+'&');
    hmac.update(sigParam, 'utf8');
    var sig = hmac.digest('base64');

    var postData = util.format('amt=%d&appid=%s&appmode=%d&goodsmeta=%s&goodsurl=%s&openid=%s&openkey=%s&payitem=%s&pf=%s&pfkey=%s&ts=%d&zoneid=%d&sig=%s', amt, appid, appmode, urlencode(goodsmeta), urlencode(goodsurl), openid, openkey, urlencode(payitem), pf, pfkey, ts, zoneid, urlencode(sig)); 
    if( manyouid ) {
        postData = util.format('amt=%d&appid=%s&appmode=%d&goodsmeta=%s&goodsurl=%s&manyouid=%s&openid=%s&openkey=%s&payitem=%s&pf=%s&pfkey=%s&ts=%d&zoneid=%d&sig=%s', amt, 
            appid, appmode, urlencode(goodsmeta), urlencode(goodsurl), manyouid, openid, openkey, urlencode(payitem), pf, pfkey, ts, zoneid, urlencode(sig));  
    }

    requestAPI(url, postData, callback);
}

function getPayToken(openid, openkey, pf, pfkey, callback) {
    var method = 'POST';
    var url = '/v3/pay/get_token';
    
    var pf = pf || 'qzone';
    var zoneid = config.ServerId;
    var ts = common.getTime();
    var discountid = 'UM131012161439631';

    var strParam = util.format('appid=%s&discountid=%s&openid=%s&openkey=%s&pf=%s&pfkey=%s&tokentype=%s&ts=%d&version=v3&zoneid=%d', appid, discountid, openid, openkey, pf, pfkey, 1, ts, zoneid); 
    var sigParam = util.format('%s&%s&%s', method, urlencode(url), urlencode(strParam));
    var hmac = crypto.createHmac('sha1', appkey+'&');
    hmac.update(sigParam, 'utf8');
    var sig = hmac.digest('base64');

    var postData = util.format('appid=%s&discountid=%s&openid=%s&openkey=%s&pf=%s&pfkey=%s&tokentype=%s&ts=%d&version=v3&zoneid=%d&sig=%s', appid, discountid, openid, openkey, pf, pfkey, 1, ts, zoneid, urlencode(sig)); 

    requestAPI(url, postData, callback);
}

function confirmDelivery(openid, openkey, data, callback) {
    var method = 'POST';
    var url = '/v3/pay/confirm_delivery';

    var amt = data.amt;
    var billno = data.billno;
    var payamt_coins = data.payamt_coins;

    var payitem = data.payitem; 
    var pf = 'qzone';
    var token = data.token;
    var ts = data.ts;
    var zoneid = data.zoneid;
    var errno = 0;
    

    var strParam = util.format('amt=%s&appid=%s&billno=%s&openid=%s&openkey=%s&payamt_coins=%s&payitem=%s&pf=%s&provide_errno=%s&providetype=0&pubacct_payamt_coins=&token_id=%s&ts=%s&version=v3&zoneid=%s', amt, appid, billno, openid, openkey, payamt_coins, payitem, pf, errno, token, ts, zoneid); 
    var sigParam = util.format('%s&%s&%s', method, urlencode(url), urlencode(strParam));
    var hmac = crypto.createHmac('sha1', appkey+'&');
    hmac.update(sigParam, 'utf8');
    var sig = hmac.digest('base64');

    var postData = util.format('amt=%s&appid=%s&billno=%s&openid=%s&openkey=%s&payamt_coins=%s&payitem=%s&pf=%s&provide_errno=%s&providetype=%s&pubacct_payamt_coins=&token_id=%s&ts=%s&version=v3&zoneid=%s&sig=%s', amt, appid, urlencode(billno), openid, openkey, payamt_coins, urlencode(payitem), pf, errno, 0, urlencode(token), ts, zoneid, urlencode(sig)); 

    requestAPI(url, postData, callback);
}

function informTaskComplete(openid, openkey, pf, pfkey, contractid, callback) {
    var method = 'POST';
    var url = '/v3/pay/inform_task_completed';
    
    pf = pf || 'qzone';
    var zoneid = config.ServerId;
    var ts = common.getTime();

    var strParam = util.format('appid=%s&contractid=%s&openid=%s&openkey=%s&pf=%s&pfkey=%s&ts=%d&zoneid=%d', appid, contractid, openid, openkey, pf, pfkey, ts, zoneid); 
    var sigParam = util.format('%s&%s&%s', method, urlencode(url), urlencode(strParam));
    var hmac = crypto.createHmac('sha1', appkey+'&');
    hmac.update(sigParam, 'utf8');
    var sig = hmac.digest('base64');

    var postData = util.format('appid=%s&contractid=%s&openid=%s&openkey=%s&pf=%s&pfkey=%s&ts=%d&zoneid=%d&sig=%s', appid, contractid, openid, openkey, pf, pfkey, ts, zoneid, urlencode(sig)); 

    requestAPI(url, postData, callback);
}

function checkPurviewActivity(openid, openkey, pf, pfkey, actid, giftid, callback) {
    var method = 'POST';
    var url = '/v3/user/check_purview_activity';
    
    pf = pf || 'qzone';
    var zoneid = config.ServerId;
    var ts = common.getTime();

    var strParam = util.format('actid=%s&appid=%s&giftid=%s&openid=%s&openkey=%s&pf=%s&pfkey=%s&ts=%d&zoneid=%d', actid, appid, giftid, openid, openkey, pf, pfkey, ts, zoneid); 
    var sigParam = util.format('%s&%s&%s', method, urlencode(url), urlencode(strParam));
    var hmac = crypto.createHmac('sha1', appkey+'&');
    hmac.update(sigParam, 'utf8');
    var sig = hmac.digest('base64');

    var postData = util.format('actid=%s&appid=%s&giftid=%s&openid=%s&openkey=%s&pf=%s&pfkey=%s&ts=%d&zoneid=%d&sig=%s', actid, appid, giftid, openid, openkey, pf, pfkey, ts, zoneid, urlencode(sig)); 

    requestAPI(url, postData, callback);
}

function getUserInfo(openid, openkey, pf, callback) {
    invokeAPI('/v3/user/get_info', openid, openkey, pf, callback);
}

function isAppOnPanel(openid, openkey, pf, callback) {
    invokeAPI('/v3/spread/is_app_onpanel', openid, openkey, pf, callback);
}

function invokeAPI(url, openid, openkey, pf, callback){
    var method = 'POST';
    var strParam = util.format('appid=%s&format=json&openid=%s&openkey=%s&pf=%s', 
                                        appid, openid, openkey, pf);
    var sigParam = util.format('%s&%s&%s', method, urlencode(url), urlencode(strParam));
    var hmac = crypto.createHmac('sha1', appkey+'&');
    hmac.update(sigParam, 'utf8');
    var sig = hmac.digest('base64');

    var postData = util.format('openid=%s&openkey=%s&appid=%s&pf=%s&sig=%s',
                        openid, openkey, appid, pf, urlencode(sig));

    requestAPI(url, postData, callback);
}

function requestAPI(url, postData, callback){
    //var host = '119.147.19.43';
    host = 'openapi.tencentyun.com';

    var options = {
        host: host,
        path: url,
        method: 'POST',
        rejectUnauthorized: false,
        headers: {'Content-Length':postData.length}
    };

    var req = https.request(options, function(res) {
        var chunks = [];
        res.on('data', function(chunk){
            chunks.push(chunk);
        });

        res.on('end', function(){
            var data = Buffer.concat(chunks).toString();
            try{
                data = JSON.parse(data);
            }catch(error){
                data = null;
            }
            callback && callback(data);
        });
    });

    req.on('error', function(){
        callback && callback(null);
    });

    req.end(postData);
}

function handleQueryUserReq(req, res) {
    
    var openid = req.openid;
    var taskId = req.task_id || 0;
    // 台湾乐元素激励跳转预注册领取奖励接口
    var twRegisterPromotion = req.tw_register_promotion || 0; 
    var existUid = gUsers[openid];
    if( !existUid ) {
        res.writeHead(200, common.htmlHeaders);
        res.end(util.format('%j', {ret:2, msg:'user not exist'}));
        return;
    }       
    
    // 请求game数据
    var url = util.format('%s?mod=gm&act=get_user&uid=%d&args=%j',
            getGameServer(existUid), existUid, {key:config.GMAuth, task_id:taskId, tw_register_promotion:twRegisterPromotion});

    common.httpGet(url, function(data){
        var resp = {ret:0, login:0, today_login:0, login_days:0, login_count:0, level:0, un:'',promotion_got:0};

        if( data && data.code == 0 ) {
            resp.login = data.data.login;
            resp.today_login = data.data.today_login;
            resp.login_days = data.data.login_days; 
            resp.login_count = data.data.login_count; 
            resp.level = data.data.level;
            resp.un = data.data.un;
            resp.promotion_got = data.data.promotion_got || 0;
        }
        
        res.writeHead(200, common.htmlHeaders);
        res.end(util.format('%j', resp));
    }, true);
}   

function handleCheckUser(req, res) {
    var openid = req.openid;
    var uid = gUsers[openid];
    var resp = {'code':0, 'data':{}};
    if (!uid) {
        resp.code = 1;
        res.writeHead(200, common.htmlHeaders);
        res.end(JSON.stringify(resp));
    }

    var url = util.format('%s?mod=gm&act=gm&uid=%d&args=%j',
        getGameServer(uid), uid, {key:config.GMAuth, method:'get'});
    common.httpGet(url, function(data) {
        if (data && data.code == 0) {
            resp.data = {'userid':uid, 'username':data.data.info.un};
        } else {
            resp.code = 2;
        }

        res.writeHead(200, common.htmlHeaders);
        res.end(JSON.stringify(resp));
    }, true);
}


exports.buyGoods = buyGoods;
exports.informTaskComplete = informTaskComplete;
exports.checkPurviewActivity = checkPurviewActivity;
exports.getUserInfo = getUserInfo;
exports.startWebServer = startWebServer;
exports.getPayToken = getPayToken;
exports.isAppOnPanel = isAppOnPanel;

/*buyGoods('8D3987CA331D5797A213A0FF51D27C4D','C843F9CFB7567B8FF7ACF034454DD788','qzone','9bdfd5fdcdde61b019e957a2e6de1bed');
var data = { amt: '100',
  appid: '100712667',
  billno: '-APPDJSX14984-20130712-1739150160',
  openid: '8D3987CA331D5797A213A0FF51D27C4D',
  payamt_coins: '0',
  payitem: 'c10*10*1',
  providetype: '0',
  pubacct_payamt_coins: '',
  token: 'E60462880317CB6799D02B4532E97B2210437',
  ts: '1373621955',
  version: 'v3',
  zoneid: '0',
  sig: 'DXTIdTtqa7ZKvpbYdvZ4A6+kzkY=' };
confirmDelivery('8D3987CA331D5797A213A0FF51D27C4D', 'C843F9CFB7567B8FF7ACF034454DD788', data);
*/

//informTaskComplete('8D3987CA331D5797A213A0FF51D27C4D', '8AF72053A5CC6E22A01F05A0426ED1E1','qzone', 'f773a8f96731621ac90f50790c04e3cb', '100712667T2201308010001', function(data){console.log(data);});
